package com.enterprise.support.utility;


import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.util.Date;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;

/**
 * Created by IntelliJ IDEA.
 * User: Zhanggaojiang
 * Date: 11-1-19
 * Time: 上午10:36
 * Email: z82422@gmail.com
 * 邮件发送
 */
public class MailUtility {
    private static String xmlconfig = "";

    static {
        xmlconfig = FileUtility.readStream(FileUtility.loadJarResources("mail/mail-config.xml"), "GBK");
    }

    private String mailSpec;
    private String bodyTemplate;
    private Message msg;
    private String MAIL_SMTP_HOST;
    private String MAIL_SMTP_PORT;
    private String MAIL_USER_NAME;
    private String MAIL_USER_PASSWORD;
    private boolean MAIL_AUTHENTICATOR;
    private String CONTENT_TRANSFER_ENCODING;
    private String SUB_TYPE;
    private String MAIL_HOST;
    private String MAIL_PORT;
    private boolean SESSION_DEBUG_MESSAGE_FLAG;
    private String DEFAULT_SENDER_MAIL_ADDRESS;
    private String DEFAULT_SENDER_NAME;
    private String CONTENT_TYPE;
    private String CHARSET_TYPE;
    private String PLAIN_CONTENT_TYPE;
    private String HTML_CONTENT_TYPE;
    private String ENCODING_TYPE;
    private String BODY_TEMPLATE_DIRECTORY;
    private String BODY_TEMPLATE_HTML;
    private String IMG_SERVER_IP;
    private String IMG_SERVER_PORT;
    private boolean SAVE_RESOLVEDHTML_FLAG;
    private String SAVE_RESOLVEDHTML_DIR;
    private boolean TEST_MODE;
    private String TEST_RECEIVERS[];

    public static String getConfigValue(String xpath, String... defaultValue) {
        String value = FileUtility.xpath(xpath, xmlconfig);
        if (Validation.isEmpty(value) && !Validation.isEmpty(defaultValue)) {
            value = defaultValue[0];
        }
        return value;
    }

    public static boolean getConfigBoolean(String xpath, String... defaultValue) {
        return new Boolean(getConfigValue(xpath, defaultValue));
    }

    public static int getConfigInt(String xpath, String... defaultValue) {
        return DataFormat.ObjectFormatInteger(getConfigValue(xpath, defaultValue));
    }

    private void checkTestOption() throws Exception {
        TEST_MODE = getConfigBoolean("/mail-config/test-mode/text()", String.valueOf(TEST_MODE));
        TEST_RECEIVERS = new String[]{};
        if (TEST_MODE) {
            StringTokenizer st = new StringTokenizer(getConfigValue("/mail-config/test-receivers/text()", ""), ",");
            TEST_RECEIVERS = new String[st.countTokens()];
            for (int i = 0; st.hasMoreTokens(); i++) {
                TEST_RECEIVERS[i] = (String) st.nextElement();
            }
            if (TEST_RECEIVERS.length == 0) {
                throw new Exception("ENTERPRISE_MAIL_006,TEST-RECEIVERS Setting Error");
            }
        }
    }

    private void setMailSpec(String mailSpec) throws Exception {
        this.mailSpec = "/mail-config/spec[@name='" + mailSpec + "']/";
        MAIL_HOST = getConfigValue(this.mailSpec + "mail-host/text()", MAIL_HOST);
        MAIL_PORT = getConfigValue(this.mailSpec + "mail-port/text()", MAIL_PORT);
        MAIL_USER_NAME = getConfigValue(this.mailSpec + "mail-user-name/text()", MAIL_USER_NAME);
        MAIL_USER_PASSWORD = getConfigValue(this.mailSpec + "mail-user-password/text()", MAIL_USER_PASSWORD);
        MAIL_AUTHENTICATOR = new Boolean(getConfigValue(this.mailSpec + "mail-authenticator/text()", MAIL_USER_PASSWORD));
        SESSION_DEBUG_MESSAGE_FLAG = getConfigBoolean(this.mailSpec + "session-debug-message-flag/text()", new Boolean(SESSION_DEBUG_MESSAGE_FLAG).toString());
        DEFAULT_SENDER_MAIL_ADDRESS = getConfigValue(this.mailSpec + "default-sender-mail-address/text()", DEFAULT_SENDER_MAIL_ADDRESS);
        DEFAULT_SENDER_NAME = getConfigValue(this.mailSpec + "default-sender-name/text()", DEFAULT_SENDER_NAME);
        CONTENT_TYPE = getConfigValue(this.mailSpec + "content-type/text()", CONTENT_TYPE);
        CHARSET_TYPE = getConfigValue(this.mailSpec + "charset-type/text()", CHARSET_TYPE);
        PLAIN_CONTENT_TYPE = getConfigValue(this.mailSpec + "plain-content-type/text()", PLAIN_CONTENT_TYPE);
        HTML_CONTENT_TYPE = getConfigValue(this.mailSpec + "html-content-type/text()", HTML_CONTENT_TYPE);
        ENCODING_TYPE = getConfigValue(this.mailSpec + "encoding-type/text()", ENCODING_TYPE);
        PLAIN_CONTENT_TYPE = "text/plain;charset=" + CHARSET_TYPE;
        HTML_CONTENT_TYPE = "text/html;charset=" + CHARSET_TYPE;
    }


    public void printCurrentConfigInfo() {
        System.out.println("-------------------------------------------------------------------");
        System.out.println("[ " + mailSpec + "],[ " + bodyTemplate + " ]");
        System.out.println(" *TEST_MODE                   " + TEST_MODE);
        System.out.print(" *TEST_RECEIVERS              ");
        for (int i = 0; i < TEST_RECEIVERS.length; i++)
            System.out.print(TEST_RECEIVERS[i] + " ");

        System.out.println("");
        System.out.println(" *MAIL_HOST                   " + MAIL_HOST);
        System.out.println(" *MAIL_PORT                   " + MAIL_PORT);
        System.out.println(" *SESSION_DEBUG_MESSAGE_FLAG  " + SESSION_DEBUG_MESSAGE_FLAG);
        System.out.println(" *DEFAULT_SENDER_MAIL_ADDRESS " + DEFAULT_SENDER_MAIL_ADDRESS);
        System.out.println(" *DEFAULT_SENDER_NAME         " + DEFAULT_SENDER_NAME);
        System.out.println(" *CONTENT_TYPE                " + CONTENT_TYPE);
        System.out.println(" *CHARSET_TYPE                " + CHARSET_TYPE);
        System.out.println(" *PLAIN_CONTENT_TYPE          " + PLAIN_CONTENT_TYPE);
        System.out.println(" *HTML_CONTENT_TYPE           " + HTML_CONTENT_TYPE);
        System.out.println(" *ENCODING_TYPE               " + ENCODING_TYPE);
        System.out.println(" *BODY_TEMPLATE_DIRECTORY     " + BODY_TEMPLATE_DIRECTORY);
        System.out.println(" *BODY_TEMPLATE_HTML          " + BODY_TEMPLATE_HTML);
        System.out.println(" *IMG_SERVER_IP               " + IMG_SERVER_IP);
        System.out.println(" *IMG_SERVER_PORT             " + IMG_SERVER_PORT);
        System.out.println(" *SAVE_RESOLVEDHTML_FLAG      " + SAVE_RESOLVEDHTML_FLAG);
        System.out.println(" *SAVE_RESOLVEDHTML_DIR       " + SAVE_RESOLVEDHTML_DIR);
        System.out.println("-------------------------------------------------------------------");
    }

    private void setDefaultFromAddress() throws Exception {
        setFromMailAddress(DEFAULT_SENDER_MAIL_ADDRESS, DEFAULT_SENDER_NAME);
    }

    private void setMimeMessage(Session session) throws Exception {
        try {
            msg = new MimeMessage(session);
            msg.setSentDate(new Date());
        } catch (MessagingException e) {
            throw new Exception("LAF_MAL_002 Mail Contents Setting Error , Message.setSentDate()" + e.getMessage(), e);
        }
    }

    private Session getSession(boolean debugMode) {
        Properties props = new Properties();
        props.put(MAIL_SMTP_HOST, MAIL_HOST);
        props.put(MAIL_SMTP_PORT, MAIL_PORT);
        Session session = null;
        if (MAIL_AUTHENTICATOR) {
            props.put("mail.smtp.auth", "true");
            session = Session.getDefaultInstance(props, new Authenticator() {
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(MAIL_USER_NAME, MAIL_USER_PASSWORD);
                }
            });
        } else {
            session = Session.getDefaultInstance(props);
        }
        session.setDebug(debugMode);

        return session;
    }

    public MailUtility(String mailSpec) throws Exception {
        this.mailSpec = "";
        this.bodyTemplate = "/mail-config/body-template/html";
        msg = null;
        MAIL_SMTP_HOST = "mail.smtp.host";
        MAIL_SMTP_PORT = "mail.smtp.port";
        CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
        SUB_TYPE = "mixed";
        MAIL_HOST = "localhost";
        MAIL_PORT = "25";
        MAIL_USER_NAME = "z87422@163.com";
        MAIL_USER_PASSWORD = "xiaojiang";
        MAIL_AUTHENTICATOR = false;
        SESSION_DEBUG_MESSAGE_FLAG = true;
        DEFAULT_SENDER_MAIL_ADDRESS = "admin@abc.com";
        DEFAULT_SENDER_NAME = "\uBCF4\uB0B4\uB294 \uC0AC\uB78C";
        CONTENT_TYPE = "7bit";
        CHARSET_TYPE = "euc-kr";
        PLAIN_CONTENT_TYPE = "text/plain;charset=euc-kr";
        HTML_CONTENT_TYPE = "text/html;charset=euc-kr";
        ENCODING_TYPE = "Q";
        BODY_TEMPLATE_DIRECTORY = "";
        BODY_TEMPLATE_HTML = "";
        IMG_SERVER_IP = "";
        IMG_SERVER_PORT = "";
        SAVE_RESOLVEDHTML_FLAG = false;
        SAVE_RESOLVEDHTML_DIR = "";
        TEST_MODE = false;
        checkTestOption();
        setMailSpec("default");
        if (!mailSpec.equals("default")) setMailSpec(mailSpec);
        setMimeMessage(getSession(SESSION_DEBUG_MESSAGE_FLAG));
        setDefaultFromAddress();
    }

    public MailUtility() throws Exception {
        this("default");
    }

    public void setFromMailAddress(String mailAddress, String name) throws Exception {
        try {
            InternetAddress sender = new InternetAddress((mailAddress == null ? DEFAULT_SENDER_MAIL_ADDRESS : mailAddress), name == null ? DEFAULT_SENDER_NAME : name, CHARSET_TYPE);
            msg.setFrom(sender);
        } catch (MessagingException e) {
            throw new Exception("LAF_MAL_005 Mail Address Setting Error, MailAddress[" + mailAddress + "] name[" + name + "]", e);
        } catch (UnsupportedEncodingException e) {
            throw new Exception("LAF_MAL_003 Found Encoding Error, InternetAddress Constructor - MailAddress[" + mailAddress + "] name[" + name + "]", e);
        }
    }

    public void setFromMailAddress(String mailAddress) throws Exception {
        try {
            InternetAddress sender = new InternetAddress(mailAddress);
            msg.setFrom(sender);
        } catch (MessagingException e) {
            throw new Exception("LAF_MAL_005 Mail Address Setting Error, MailAddress[" + mailAddress + "]", e);
        }
    }

    public void setToMailAddress(String mailAddress, String name) throws Exception {
        setMailAddress(mailAddress, name, Message.RecipientType.TO);
    }

    public void setCcMailAddress(String mailAddress, String name) throws Exception {
        setMailAddress(mailAddress, name, Message.RecipientType.CC);
    }

    public void setBccMailAddress(String mailAddress, String name) throws Exception {
        setMailAddress(mailAddress, name, Message.RecipientType.BCC);
    }

    private void setMailAddress(String mailAddress, String name, Message.RecipientType type) throws Exception {
        setMailAddress(new String[]{mailAddress}, new String[]{name}, type);
    }

    public void setToMailAddress(String mailAddress[], String name[]) throws Exception {
        setMailAddress(mailAddress, name, Message.RecipientType.TO);
    }

    public void setCcMailAddress(String mailAddress[], String name[]) throws Exception {
        setMailAddress(mailAddress, name, Message.RecipientType.CC);
    }

    public void setBccMailAddress(String mailAddress[], String name[]) throws Exception {
        setMailAddress(mailAddress, name, Message.RecipientType.BCC);
    }

    private void setMailAddress(String mailAddress[], String name[], Message.RecipientType type) throws Exception {
        int i = 0;
        try {
            InternetAddress recipients[] = new InternetAddress[mailAddress.length];
            for (i = 0; i < mailAddress.length; i++)
                recipients[i] = new InternetAddress(mailAddress[i], name[i]);

            msg.setRecipients(type, recipients);
        } catch (MessagingException e) {
            throw new Exception("LAF_MAL_005 Mail Address Setting Error, MailAddress[" + mailAddress[i] + "] name[" + name[i] + "] Type[" + type + "]", e);
        } catch (UnsupportedEncodingException e) {
            throw new Exception("LAF_MAL_003 Found Encoding Error, InternetAddress Constructor - MailAddress[" + mailAddress[i] + "] name[" + name[i] + "] Type[" + type + "]", e);
        }
    }

    public void setToMailAddress(String mailAddress) throws Exception {
        setMailAddress(mailAddress, Message.RecipientType.TO);
    }

    public void setCcMailAddress(String mailAddress) throws Exception {
        setMailAddress(mailAddress, Message.RecipientType.CC);
    }

    public void setBccMailAddress(String mailAddress) throws Exception {
        setMailAddress(mailAddress, Message.RecipientType.BCC);
    }

    private void setMailAddress(String mailAddress, Message.RecipientType type) throws Exception {
        setMailAddress(new String[]{mailAddress}, type);
    }

    public void setToMailAddress(String mailAddress[]) throws Exception {
        setMailAddress(mailAddress, Message.RecipientType.TO);
    }

    public void setCcMailAddress(String mailAddress[]) throws Exception {
        setMailAddress(mailAddress, Message.RecipientType.CC);
    }

    public void setBccMailAddress(String mailAddress[]) throws Exception {
        setMailAddress(mailAddress, Message.RecipientType.BCC);
    }

    private void setMailAddress(String mailAddress[], Message.RecipientType type) throws Exception {
        int i = 0;
        try {
            InternetAddress recipients[] = new InternetAddress[mailAddress.length];
            for (i = 0; i < mailAddress.length; i++)
                recipients[i] = new InternetAddress(mailAddress[i]);

            msg.setRecipients(type, recipients);
        } catch (MessagingException e) {
            throw new Exception("LAF_MAL_005 Mail Address Setting Error, MailAddress[" + mailAddress[i] + "] Type[" + type + "]", e);
        }
    }

    public void send() throws Exception {
        try {
            if (TEST_MODE) {
                System.out.println("Requested config.mail will be sent to TEST-RECEIVERS(TEST-MODE in mail-config.xml is true.).");
                setToMailAddress(TEST_RECEIVERS);
            }

            Transport.send(msg);
        } catch (MessagingException e) {
            throw new Exception("LAF_MAL_004 Mail Send Error , Transport.send Message[" + msg + "]", e);
        }
    }

    public void setSubject(String subject) throws Exception {
        try {
            ((MimeMessage) msg).setSubject(subject, CHARSET_TYPE);
        } catch (MessagingException e) {
            throw new Exception("LAF_MAL_001 Mail Subject Setting Error " + e.getMessage(), e);
        }
    }

    public void setText(String textMessage) throws Exception {
        try {
            msg.setContent(textMessage, PLAIN_CONTENT_TYPE);
            msg.setHeader(CONTENT_TRANSFER_ENCODING, CONTENT_TYPE);
            msg.saveChanges();
        } catch (MessagingException e) {
            throw new Exception("LAF_MAL_002 Mail Contents Setting Error " + e.getMessage(), e);
        }
    }

    public void setHtml(String htmlMessage) throws Exception {
        try {
            msg.setDataHandler(new DataHandler(new ByteArrayDataSource(htmlMessage, HTML_CONTENT_TYPE, CHARSET_TYPE)));
            msg.setHeader(CONTENT_TRANSFER_ENCODING, CONTENT_TYPE);
            msg.saveChanges();
        } catch (MessagingException e) {
            throw new Exception("LAF_MAL_002 Mail Contents Setting Error " + e.getMessage(), e);
        }
    }

    private void attachFileSourceArray(MimeMultipart multiPart, String fileNames[]) throws MessagingException, UnsupportedEncodingException {
        MimeBodyPart fileBodyPartArray[] = (MimeBodyPart[]) null;
        if (fileNames == null) fileBodyPartArray = new MimeBodyPart[0];
        else fileBodyPartArray = new MimeBodyPart[fileNames.length];
        for (int i = 0; i < fileBodyPartArray.length; i++) {
            fileBodyPartArray[i] = new MimeBodyPart();
            FileDataSource fileSource = new FileDataSource(fileNames[i]);
            fileBodyPartArray[i].setDataHandler(new DataHandler(fileSource));
            fileBodyPartArray[i].setFileName(MimeUtility.encodeText(fileSource.getName(), CHARSET_TYPE, ENCODING_TYPE));
            multiPart.addBodyPart(fileBodyPartArray[i]);
        }

    }

    public void setTextAndFile(String textMessage, String fileName) throws Exception {
        setTextAndFile(textMessage, new String[]{fileName});
    }

    public void setTextAndFile(String textMessage, String fileNames[]) throws Exception {
        try {
            MimeBodyPart textPart = new MimeBodyPart();
            textPart.setText(textMessage, CHARSET_TYPE);
            MimeMultipart multiPart = new MimeMultipart();
            multiPart.addBodyPart(textPart);
            attachFileSourceArray(multiPart, fileNames);
            multiPart.setSubType(SUB_TYPE);
            msg.setContent(multiPart);
            msg.saveChanges();
        } catch (MessagingException e) {
            throw new Exception("LAF_MAL_002 Mail Contents Setting Error " + e.getMessage(), e);
        } catch (UnsupportedEncodingException e) {
            throw new Exception("LAF_MAL_003 Found Encoding Error, MimeUtility.encodeText - Current CHARSET_TYPE[" + CHARSET_TYPE + "] ENCODING_TYPE[" + ENCODING_TYPE + "]", e);
        }
    }

    public void setHtmlAndFile(String htmlMessage, String fileName) throws Exception {
        setHtmlAndFile(htmlMessage, new String[]{fileName});
    }

    public void setHtmlAndFile(String htmlMessage, String fileNames[]) throws Exception {
        try {
            MimeBodyPart htmlPart = new MimeBodyPart();
            htmlPart.setDataHandler(new DataHandler(new ByteArrayDataSource(htmlMessage, HTML_CONTENT_TYPE, CHARSET_TYPE)));
            htmlPart.setHeader(CONTENT_TRANSFER_ENCODING, CONTENT_TYPE);
            MimeMultipart multiPart = new MimeMultipart();
            multiPart.addBodyPart(htmlPart);
            attachFileSourceArray(multiPart, fileNames);
            multiPart.setSubType("mixed");
            msg.setContent(multiPart);
            msg.saveChanges();
        } catch (MessagingException e) {
            throw new Exception("LAF_MAL_002 Mail Contents Setting Error " + e.getMessage(), e);
        } catch (UnsupportedEncodingException e) {
            throw new Exception("LAF_MAL_003 Found Encoding Error, MimeUtility.encodeText - Current CHARSET_TYPE[" + CHARSET_TYPE + "] ENCODING_TYPE[" + ENCODING_TYPE + "]", e);
        }
    }

    public String loadHtml(String htmlTemplate, Enterprise var) throws Exception {
        String resultStr = new String();
        try {
            String htmlName = getConfigValue(bodyTemplate + "[@name='" + htmlTemplate + "']/text()");
            String htmlStr = (FileUtility.readStream(FileUtility.loadJarResources(htmlName), CHARSET_TYPE));
            if (!Validation.isEmpty(htmlStr)) {
                for (String key : (Set<String>) var.keySet()) {
                    htmlStr = htmlStr.replace("${" + key + "}", var.getString(key));
                }
            }
            resultStr = htmlStr;
        } catch (Exception e) {
            throw new Exception("LAF_MAL_002  Mail Contents Setting Error " + e.getMessage(), e);
        }
        return resultStr;
    }

    class ByteArrayDataSource implements DataSource {

        private byte data[];
        private String type;

        public ByteArrayDataSource(String data, String type, String charSet) {
            try {
                this.data = data.getBytes(charSet);
            } catch (UnsupportedEncodingException unsupportedencodingexception) {
            }
            this.type = type;
        }

        public InputStream getInputStream() throws IOException {
            if (data == null) throw new IOException("no data");
            else return new ByteArrayInputStream(data);
        }

        public OutputStream getOutputStream() throws IOException {
            throw new IOException("cannot do this");
        }

        public String getContentType() {
            return type;
        }

        public String getName() {
            return "dummy";
        }
    }

    public static void main(String[] args) {
        try {

            Enterprise vars = new Enterprise();
            vars.set("username", "EunBong, Choi");
            vars.set("publishdate", DataFormat.DateFormtString("yyyy年MM月dd日 hh:mm", new Date()));

            MailUtility mail = new MailUtility("qq");
            mail.printCurrentConfigInfo();
            //mail.setFromMailAddress(null);
            mail.setSubject("协会群发测试邮件");
            mail.setHtml(mail.loadHtml("forward", vars));
            mail.setToMailAddress("404700102@qq.com");
            mail.send();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return;
    }
}

